﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Validation;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Hrm.Core;
using System.Data.Entity.Core.Objects;

namespace Hrm.EntityFramework
{
    public partial class EfRepository<T> : IRepository<T> where T : Entity
    {
        #region Fields

        private readonly IDbContext _context;

        private IDbSet<T> _entities;

        #endregion

        #region Properties

        public virtual IQueryable<T> Table
        {
            get
            {
                return this.Entities;
            }
        }

        public virtual IQueryable<T> TableNoTracking
        {
            get
            {
                return this.Entities.AsNoTracking();
            }
        }

        protected virtual IDbSet<T> Entities
        {
            get
            {
                if (_entities == null)
                    _entities = _context.Set<T>();
                return _entities;
            }
        }

        #endregion

        #region Ctor

        public EfRepository(IDbContext context)
        {
            this._context = context;
        }

        #endregion

        #region Methods
        public IList<T> ExecuteStoredProcedureList(string commandText, params object[] parameters)
        {
            return this._context.ExecuteStoredProcedureList<T>(commandText, parameters);
        }

        public IEnumerable<T> SqlQuery(string sql, params object[] parameters)
        {
            return this._context.SqlQuery<T>(sql, parameters);
        }

        public virtual int ExecuteSqlCommand(string sql, bool doNotEnsureTransaction = false, int? timeout = null, params object[] parameters)
        {
            return this._context.ExecuteSqlCommand(sql, doNotEnsureTransaction, timeout, parameters);
        }

        public virtual T GetById(object id)
        {
            return this.Entities.Find(id);
        }

        public virtual T Get(Func<T, bool> predicate)
        {
            return this.Entities.SingleOrDefault(predicate);
        }


        public virtual IEnumerable<T> GetAll()
        {
            return this.Entities;
        }

        public virtual IEnumerable<T> GetList(Func<T, bool> predicate)
        {
            return this.Entities.Where(predicate);
        }

        public virtual int Insert(T entity, bool isSave = true)
        {
            try
            {
                if (entity == null)
                    throw new ArgumentNullException("entity");
                entity.CreateDatetime = DateTime.Now;
                this.Entities.Add(entity);
                if (isSave)
                    return this._context.SaveChanges();
                else
                    return 0;
            }
            catch (DbEntityValidationException dbEx)
            {
                var msg = string.Empty;
                foreach (var validationErrors in dbEx.EntityValidationErrors)
                    foreach (var validationError in validationErrors.ValidationErrors)
                        msg += string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage) + Environment.NewLine;
                var fail = new Exception(msg, dbEx);
                throw fail;
            }
        }

        public virtual void Insert(IEnumerable<T> entities, bool isSave = true)
        {
            try
            {
                if (entities == null)
                    throw new ArgumentNullException("entities");
                foreach (var entity in entities)
                    this.Entities.Add(entity);
                if (isSave)
                    this._context.SaveChanges();
            }
            catch (DbEntityValidationException dbEx)
            {
                var msg = string.Empty;
                foreach (var validationErrors in dbEx.EntityValidationErrors)
                    foreach (var validationError in validationErrors.ValidationErrors)
                        msg += string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage) + Environment.NewLine;

                var fail = new Exception(msg, dbEx);
                throw fail;
            }
        }

        public virtual int Update(T entity, bool isSave = true)
        {
            try
            {
                entity.UpdateDatetime = DateTime.Now;
                if (entity == null)
                    throw new ArgumentNullException("entity");
                if (isSave)
                    return this._context.SaveChanges();
                else
                    return 0;
            }
            catch (DbEntityValidationException dbEx)
            {
                var msg = string.Empty;
                foreach (var validationErrors in dbEx.EntityValidationErrors)
                    foreach (var validationError in validationErrors.ValidationErrors)
                        msg += Environment.NewLine + string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);

                var fail = new Exception(msg, dbEx);
                throw fail;
            }
        }

        public virtual void Update(IEnumerable<T> entities, bool isSave = true)
        {
            try
            {
                if (entities == null)
                    throw new ArgumentNullException("entities");
                if (isSave)
                    this._context.SaveChanges();
            }
            catch (DbEntityValidationException dbEx)
            {
                var msg = string.Empty;
                foreach (var validationErrors in dbEx.EntityValidationErrors)
                    foreach (var validationError in validationErrors.ValidationErrors)
                        msg += string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage) + Environment.NewLine;
                var fail = new Exception(msg, dbEx);
                throw fail;
            }
        }

        public virtual int Delete(T entity, bool isSave = true)
        {
            try
            {
                if (entity == null)
                    throw new ArgumentNullException("entity");
                this.Entities.Remove(entity);
                if (isSave)
                    return this._context.SaveChanges();
                else
                    return 0;
            }
            catch (DbEntityValidationException dbEx)
            {
                var msg = string.Empty;

                foreach (var validationErrors in dbEx.EntityValidationErrors)
                    foreach (var validationError in validationErrors.ValidationErrors)
                        msg += Environment.NewLine + string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
                var fail = new Exception(msg, dbEx);
                throw fail;
            }
        }

        public  virtual int Delete(int id, bool isSave = true)
        {
            try
            {
                var entity = this.Entities.Find(id);
                if (entity == null)
                    throw new ArgumentNullException("entity");
                this.Entities.Remove(entity);
                if (isSave)
                    return this._context.SaveChanges();
                else
                    return 0;
            }
            catch (DbEntityValidationException dbEx)
            {
                var msg = string.Empty;

                foreach (var validationErrors in dbEx.EntityValidationErrors)
                    foreach (var validationError in validationErrors.ValidationErrors)
                        msg += Environment.NewLine + string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
                var fail = new Exception(msg, dbEx);
                throw fail;
            }
        }


        public virtual void Delete(IEnumerable<T> entities, bool isSave = true)
        {
            try
            {
                if (entities == null)
                    throw new ArgumentNullException("entities");
                while (entities.Count()>0)
                    this.Entities.Remove(entities.First());
                if (isSave)
                    this._context.SaveChanges();
            }
            catch (DbEntityValidationException dbEx)
            {
                var msg = string.Empty;
                foreach (var validationErrors in dbEx.EntityValidationErrors)
                    foreach (var validationError in validationErrors.ValidationErrors)
                        msg += Environment.NewLine + string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
                var fail = new Exception(msg, dbEx);
                throw fail;
            }
        }

        public virtual int Commit()
        {
            return this._context.SaveChanges();
        }
        #endregion

    }
}
